﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using TSharp.Core.Util;

namespace TSharp.Core.Util
{
    /// <summary>
    /// ini文件读写辅助
    /// <para>by tangjingbo at 2011-6-14 10:19</para>
    /// </summary>
    public sealed class IniHelper
    {
        private static readonly string DefaultIniFileFolder;
        private readonly string defaultSection;
        private readonly string filepath;
        /// <summary>
        /// Initializes a new instance of the <see cref="IniHelper"/> class.
        /// </summary>
        /// <param name="section">The section.</param>
        /// <param name="file">The file name or file full path and name.</param>
        public IniHelper(string section, string file)
        {
            defaultSection = section;
            filepath = Path.Combine(DefaultIniFileFolder, file);
        }

        private IniHelper()
            : this("config", "tsharp.ini")
        { }

        #region ctor
        /// <summary>
        /// 默认存储辅助实例
        /// </summary>
        public static readonly IniHelper Current;
        static IniHelper()
        {
            try
            {
                DefaultIniFileFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
            }
            catch
            {
                try
                {
                    DefaultIniFileFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData);
                }
                catch
                {
                    DefaultIniFileFolder = (AppDomain.CurrentDomain.SetupInformation.ApplicationBase);
                }
            }
            try
            {
                DefaultIniFileFolder = Path.Combine(DefaultIniFileFolder, "TSharper");
                var name = Process.GetCurrentProcess().ProcessName;
                if (string.IsNullOrEmpty(name))
                    name = "tsharp";
                name = name.Trim(Path.GetInvalidPathChars());
                DefaultIniFileFolder = Path.Combine(DefaultIniFileFolder, name);
                if (!Directory.Exists(DefaultIniFileFolder))
                    Directory.CreateDirectory(DefaultIniFileFolder);
            }
            catch (Exception)
            {
            }
            Current = new IniHelper();
        }

        #endregion


        /// <summary>
        /// 创建ini辅助对象
        /// </summary>
        /// <param name="section">The section.</param>
        /// <param name="file">The file name or file full path and name.</param>
        /// <returns></returns>
        public IniHelper New(string section, string file)
        {
            return new IniHelper(section, file);
        }
        private static ConcurrentDictionary<Type, PropertyDescriptorCollection> cache = new ConcurrentDictionary<Type, PropertyDescriptorCollection>();
        /// <summary>
        /// Deserializes this instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IniHelper Deserialize<T>(T o) where T : class
        {
            var type = typeof(T);
            var s = cache.GetOrAdd(type, TypeDescriptor.GetProperties);
            foreach (PropertyDescriptor p in s)
            {
                var v = Get(type.FullName, p.Name);
                if (!string.IsNullOrEmpty(v))
                    p.SetValue(o, v.ChangeType(p.PropertyType));
            }
            return this;
        }

        /// <summary>
        /// Serializes this instance.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IniHelper Serialize<T>(T o) where T : class
        {
            var type = typeof(T);
            var s = cache.GetOrAdd(type, TypeDescriptor.GetProperties);
            foreach (PropertyDescriptor p in s)
            {
                var v = p.GetValue(o).ToStringObject();
                Set(type.FullName, p.Name, v);
            }
            return this;
        }
        /// <summary>
        /// Sets the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public IniHelper Set(string key, string value)
        {
            IniWriteValue(defaultSection, key, value);
            return this;
        }
        /// <summary>
        /// Sets the specified key.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public IniHelper Set<T>(string key, T value)
        {
            var v = SafeConvert.ToStringObject(value);
            IniWriteValue(defaultSection, key, v);
            return this;
        }
        /// <summary>
        /// 设置
        /// <para>by tangjingbo at 2011-6-14 9:48</para>
        /// </summary>
        /// <param name="section">The section.</param>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public IniHelper Set(string section, string key, string value)
        {
            IniWriteValue(section, key, value);
            return this;
        }
        /// <summary>
        /// 获取默认节的key值
        /// <para>by tangjingbo at 2011-6-14 9:47</para>
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public string Get(string key)
        {
            return IniReadValue(defaultSection, key);
        }
        /// <summary>
        /// 获取默认节的key值
        /// <para>by tangjingbo at 2011-6-14 9:47</para>
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="doGet">The do get.</param>
        /// <returns></returns>
        public IniHelper Get(string key, Action<string> doGet)
        {
            doGet(Get(key));
            return this;
        }
        /// <summary>
        /// 获取直接配置节的key值
        /// <para>by tangjingbo at 2011-6-14 9:47</para>
        /// </summary>
        /// <param name="section">The section.</param>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public string Get(string section, string key)
        {
            return IniReadValue(section, key);
        }

        #region P/Invoke

        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);

        private void IniWriteValue(string section, string key, string value)
        {
            WritePrivateProfileString(section, key, value, filepath);
        }


        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal,
                                                          int size, string filePath);

        private string IniReadValue(string section, string key)
        {
            var retVal = new StringBuilder(0x9ff97);
            int num = GetPrivateProfileString(section, key, "", retVal, 0x9ff97, filepath);
            return retVal.ToString();
        }

        #endregion

    }

}
